home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / netconf / hosts.c < prev    next >
C/C++ Source or Header  |  1996-07-25  |  11KB  |  512 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <stdarg.h>
  5. #include <ctype.h>
  6. #include <netdb.h>
  7. #include "netconf.h"
  8. #include "../misc/misc.h"
  9. #include "../xconf/xconf.h"
  10. #include "netconf.m"
  11.  
  12. static NETCONF_HELP_FILE help_hosts ("hosts");
  13. NETCONF_HELP_FILE help_networks ("networks");
  14. static CONFIG_FILE f_hosts (ETC_HOSTS,help_hosts,CONFIGF_MANAGED);
  15.  
  16. void *operator new(size_t size)
  17. {
  18.     void *ret = malloc(size);
  19.     if (ret == NULL){
  20.         xconf_error (MSG_U(E_OUTOFMEMORY,"Out of memory\n"));
  21.         exit (-1);
  22.     }
  23.     return ret;
  24. }
  25.  
  26.  
  27. PUBLIC void HOST::set (const char *buf)
  28. {
  29.     /* #Specification: /etc/hosts / format
  30.         A hosts file has the following format
  31.  
  32.         # comment
  33.         ip_number    hostname [ alias ... ] [ # comment ]
  34.  
  35.         When we read /etc/hosts, we split the line in four parts, being
  36.         the ip_numer, the first name, all the alias and the comment.
  37.  
  38.         Further, when collecting the comment, we try to keep even
  39.         the space between the last data and the #.
  40.  
  41.         We hope to be able to edit normal /etc/hosts file and
  42.         rewrite it mostly respecting the original format.
  43.  
  44.         Blank line are also remembered as comment.
  45.     */
  46.     is_valid = 1;
  47.     freeall();
  48.     const char *pt = str_skip(buf);
  49.     if (isdigit(*pt)){
  50.         // First copy the ip number
  51.         char tmp[200];
  52.         char *ptd = tmp;
  53.         while (*pt > ' ') *ptd++ = *pt++;
  54.         *ptd = '\0';
  55.         ip_num.setfrom(tmp);
  56.         pt = str_skip (pt);
  57.         if (*pt > ' '){
  58.             ptd = tmp;
  59.             while (*pt > ' ') *ptd++ = *pt++;
  60.             *ptd = '\0';
  61.             name1.setfrom (tmp);
  62.             const char *endname1 = pt;
  63.             pt = str_skip (pt);
  64.             if (*pt == '#'){
  65.                 comment.setfrom (endname1);
  66.             }else if (*pt > ' '){
  67.                 const char *begother = pt;
  68.                 while (*pt != '#' && *pt != '\0') pt++;
  69.                 if (*pt == '\0'){
  70.                     others.setfrom (begother);
  71.                 }else{
  72.                     while (isspace(pt[-1])) pt--;
  73.                     int lenother = (int)(pt-begother);
  74.                     memcpy (tmp,begother,lenother);
  75.                     tmp[lenother] = '\0';
  76.                     others.setfrom (tmp);
  77.                     comment.setfrom (pt);
  78.                 }
  79.             }
  80.         }else{
  81.             is_valid = 0;
  82.         }
  83.     }else if (*pt == '#'){
  84.         comment.setfrom (buf);
  85.     }else if (pt[0] != '\0'){
  86.         // Anything else than a blank link is an error at this point
  87.         is_valid = 0;
  88.     }
  89. }
  90. /*
  91.     Setup and parse a record from /etc/hosts
  92. */
  93. PUBLIC HOST::HOST(const char *buf)
  94. {
  95.     set (buf);
  96. }
  97. PUBLIC HOST::HOST(
  98.     const char *_ip_num,
  99.     const char *_name1,
  100.     const char *_others,
  101.     const char *_comment)
  102. {
  103.     ip_num.setfrom (_ip_num);
  104.     name1.setfrom(_name1);
  105.     others.setfrom (_others);
  106.     comment.setfrom (_comment);
  107. }
  108. PUBLIC HOST::HOST()
  109. {
  110. }
  111. /*
  112.     Cleanup of the HOST, same as destructor
  113. */
  114. PRIVATE void HOST::freeall()
  115. {
  116.     ip_num.setfrom (NULL);
  117.     name1.setfrom(NULL);
  118.     others.setfrom(NULL);
  119.     comment.setfrom(NULL);
  120. }
  121. PUBLIC VIRTUAL HOST::~HOST()
  122. {
  123. }
  124.  
  125. /*
  126.     Return the principal name of a host
  127. */
  128. PUBLIC const char *HOST::getname1() const
  129. {
  130.     return name1.get();
  131. }
  132. /*
  133.     Record the principal name of a host
  134. */
  135. PUBLIC void HOST::setname1(const char *_name1)
  136. {
  137.     name1.setfrom (_name1);
  138. }
  139. /*
  140.     Return != 0 if this entry is only a comment, not a host definition.
  141. */
  142. PUBLIC int HOST::iscomment() const
  143. {
  144.     return ip_num.is_empty();
  145. }
  146. /*
  147.     Return the comment associated with an entry.
  148. */
  149. PUBLIC const char *HOST::getcomment() const
  150. {
  151.     return comment.get();
  152. }
  153. /*
  154.     Record the comment associate with a host.
  155. */
  156. PUBLIC void HOST::setcomment(const char *_comment)
  157. {
  158.     comment.setfrom (_comment);
  159. }
  160. /*
  161.     Return the alternatives names for a host (maybe more than one) as
  162.     a single string or "" is none.
  163. */
  164. PUBLIC const char *HOST::getothers() const
  165. {
  166.     return others.get();
  167. }
  168. /*
  169.     Record the others names of a host
  170. */
  171. PUBLIC void HOST::setothers(const char *_others)
  172. {
  173.     others.setfrom (_others);
  174. }
  175.  
  176. /*
  177.     Return the IP number of a host.
  178. */
  179. PUBLIC const char *HOST::getipnum() const
  180. {
  181.     return ip_num.get();
  182. }
  183. /*
  184.     Record the IP adress of a host.
  185. */
  186. PUBLIC void HOST::setipnum(const char *_ipnum)
  187. {
  188.     ip_num.setfrom (_ipnum);
  189. }
  190. /*
  191.     Output one HOST record in ascii
  192. */
  193. PUBLIC VIRTUAL void HOST::print (FILE *fout) const
  194. {
  195.     if (!ip_num.is_empty())  fprintf (fout,"%s",ip_num.get());
  196.     if (!name1.is_empty())  fprintf (fout,"\t%s",name1.get());
  197.     if (!others.is_empty())  fprintf (fout,"\t%s",others.get());
  198.     if (!comment.is_empty()) fprintf (fout,"%s",comment.get());
  199.     fputc ('\n',fout);
  200. }
  201.  
  202. /*
  203.     Return !- 0 if this is a special entry of /etc/hosts.
  204.     This entry is special because it must exist for this program
  205.     to work (and many program). The loopback and the entry of the
  206.     current machine.
  207. */
  208. PUBLIC VIRTUAL int HOST::is_special() const
  209. {
  210.     return ip_num.is_empty()
  211.         || ip_num.cmp("127.0.0.1")==0;
  212. }
  213.  
  214. /*
  215.     Free and allocate conditionnally.
  216.     Return the new allocated pointer or NULL.
  217. */
  218. char *replaceif(char *last,const char *newval)
  219. {
  220.     free (last);
  221.     char *ret = NULL;
  222.     if (newval[0] != '\0') ret = strdup (newval);
  223.     return ret;
  224. }
  225. /*
  226.     Edit a host definition.
  227.     Return -1 if the input is cancelled
  228.     Return 0 if it is accepted
  229.     Return 1 if the user request deletion of this record.
  230. */
  231. PUBLIC VIRTUAL int HOST::edit (HELP_FILE &helpfile)
  232. {
  233.     int ret = -1;
  234.     DIALOG dia;
  235.     dia.newf_str (MSG_R(F_PRIMNAME),name1);
  236.     dia.newf_str (MSG_R(F_ALIASES),others);
  237.     dia.newf_str (MSG_U(F_IPNUM,"IP number"),ip_num);
  238.     dia.newf_str (MSG_R(F_COMMENT),comment);
  239.     int nofield = 0;
  240.     while (1){
  241.         int code = dia.edit (MSG_U(T_HOSTNETDEF,"host/network definition")
  242.             ,NULL
  243.             ,helpfile
  244.             ,nofield,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL);
  245.         if (code == MENU_CANCEL || code == MENU_ESCAPE){
  246.             break;
  247.         }else if (code == MENU_DEL){
  248.             ret = 1;
  249.             break;
  250.         }else if (code ==MENU_ACCEPT){
  251.             if (!device_validip(ip_num.get(),false)){
  252.                 xconf_error (MSG_U(E_IVLIPNUM,"Invalid IP number"));
  253.             }else{
  254.                 ret = 0;
  255.                 break;
  256.             }
  257.         }
  258.     }
  259.     if (ret != 0) dia.restore();
  260.     return ret;
  261. }
  262.  
  263. PUBLIC HOSTS::HOSTS()
  264. {
  265.     cfgf = &f_hosts;
  266. }
  267.  
  268. PUBLIC VIRTUAL HOST *HOSTS::newhost (
  269.     const char *_ip_num,
  270.     const char *_name1,
  271.     const char *_others,
  272.     const char *_comment)
  273. {
  274.     return new HOST (_ip_num,_name1,_others,_comment);
  275. }
  276. PUBLIC VIRTUAL HOST *HOSTS::newhost (const char *buf)
  277. {
  278.     return new HOST (buf);
  279. }
  280. /*
  281.     Add a line to the in memory hosts table
  282.     The line may be a comment or invalid
  283. */
  284. PUBLIC VIRTUAL void HOSTS::add (const char *buf)
  285. {
  286.     HOST *pt = newhost(buf);
  287.     add (pt);
  288. }
  289. /*
  290.     Add a line to the in memory hosts table
  291. */
  292. PUBLIC VIRTUAL void HOSTS::add (
  293.     const char *_ip_num,
  294.     const char *_name1,
  295.     const char *_others,
  296.     const char *_comment)
  297. {
  298.     HOST *pt = newhost (_ip_num,_name1,_others,_comment);
  299.     add (pt);
  300. }
  301. /*
  302.     Add one item to the in memory hosts table
  303. */
  304. PUBLIC void HOSTS::add (HOST *pt)
  305. {
  306.     grow();
  307.     tb[nb++] = pt;
  308. }
  309.  
  310. /*
  311.     Read and parse a hosts file (normally /etc/hosts).
  312.     Return -1 if any error.
  313. */
  314. PUBLIC int HOSTS::read ()
  315. {
  316.     int ret = -1;
  317.     FILE *fin = cfgf->fopen ("r");
  318.     if (fin != NULL){
  319.         char buf[500];
  320.         ret = 0;
  321.         while (fgets_cont(buf,sizeof(buf)-1,fin) != -1){
  322.             add (buf);
  323.         }
  324.         fclose (fin);
  325.     }
  326.     return ret;
  327. }
  328. /*
  329.     Write a hosts file (normally /etc/hosts).
  330.     Return -1 if any error.
  331. */
  332. PUBLIC int HOSTS::write () const
  333. {
  334.     int ret = -1;
  335.     FILE *fout = cfgf->fopen ("w");
  336.     if (fout != NULL){
  337.         ret = 0;
  338.         for (int i=0; i<nb; i++) getitem(i)->print (fout);
  339.         fclose (fout);
  340.     }
  341.     return ret;
  342. }
  343. /*
  344.     Return one entry of the hosts file.
  345.     Returne NULL if the entry is out of range.
  346. */
  347. PUBLIC HOST *HOSTS::getitem(int no) const
  348. {
  349.     return (HOST*)ARRAY::getitem(no);
  350. }
  351.  
  352. /*
  353.     Lookup a host name in the "other name" string.
  354.     Return != 0 if found.
  355. */
  356. int host_lookupother (const char *others, const char *name)
  357. {
  358.     int ret = 0;
  359.     while (1){
  360.         char buf[200];
  361.         others = str_skip(others);
  362.         others = str_copyword (buf,others);
  363.         if (buf[0] == '\0') break;
  364.         if (strcmp(buf,name)==0){
  365.             ret = 1;
  366.             break;
  367.         }
  368.     }
  369.     return ret;
  370. }
  371.  
  372. /*
  373.     Find a name in the in memory host table.
  374.     Returne NULL or the entry.
  375. */
  376. PUBLIC HOST *HOSTS::getitem(const char *name) const
  377. {
  378.     HOST *ret = NULL;
  379.     if (name[0] != '\0'){
  380.         for (int i=0; i<nb; i++){
  381.             HOST *pt = getitem(i);
  382.             if (stricmp(name,pt->getname1())==0
  383.                 || host_lookupother(pt->getothers()
  384.                     ,name)){
  385.                 ret = pt;
  386.                 break;
  387.             }
  388.         }
  389.     }
  390.     return ret;
  391. }
  392. /*
  393.     Sort host by name
  394. */
  395. static int cmp_host_by_name (const void *p1, const void *p2)
  396. {
  397.     HOST *h1 = *(HOST**)p1;
  398.     HOST *h2 = *(HOST**)p2;
  399.     return strcmp(h1->getname1(),h2->getname1());
  400. }
  401. /*
  402.     Edit the file /etc/hosts or /etc/networks
  403. */
  404. PUBLIC int HOSTS::edit(
  405.     const char *title,
  406.     HELP_FILE &helpfile)
  407. {
  408.     int ret = -1;
  409.     int choice=0;
  410.     while (1){
  411.         int nbh = getnb();    // Number of entry including comments
  412.         HOST **tbsort = new HOST *[nbh];
  413.         if (tbsort != NULL){
  414.             // Extracting hosts only, no comments
  415.             // Hide information about this host
  416.             THISHOST thost;
  417.             const char *thishost_ip = thost.getipnum(0);            
  418.             int nb=0;
  419.             for (int i=0; i<nbh; i++){
  420.                 HOST *pt = getitem(i);
  421.                 if (!pt->iscomment() && !pt->is_special()
  422.                     && strcmp(pt->getipnum(),thishost_ip)!=0){
  423.                     tbsort[nb++] = pt;
  424.                 }
  425.             }
  426.             qsort (tbsort,nb,sizeof(HOST *),cmp_host_by_name);
  427.             // Format all the entries in a menu.
  428.             // The first entry is dummy. It allows addition to the list            
  429.             const char **menuopt = new const char *[(nb+2)*2+1];
  430.             int ii=0;
  431.             for (i=0; i<nb; i++,ii+=2){
  432.                 HOST *pth = tbsort[i];
  433.                 menuopt[ii] = (char*)pth->getipnum();
  434.                 char buf[300];
  435.                 sprintf (buf,"%s %s %s",pth->getname1(),pth->getothers()
  436.                     ,pth->getcomment());
  437.                 buf[50] = '\0';
  438.                 menuopt[ii+1] = strdup(buf);
  439.             }
  440.             menuopt[ii] = NULL;
  441.             //char save_what[100];
  442.             //sprintf (save_what,MSG_U(I_UPDHOSTS,"To update %s")
  443.             //    ,cfgf->getpath());
  444.             MENU_STATUS code = xconf_menu (title
  445.                 ,MSG_U(I_HOSTSDEF
  446.                     ,"Select a host/network definition to modify")
  447.                 ,helpfile
  448.                 ,NULL
  449.                 ,NULL
  450.                 ,NULL
  451.                 ,MSG_U(I_ADDDEF,"to add a new definition")
  452.                 ,menuopt,choice);
  453.             if (code == MENU_ESCAPE || code == MENU_QUIT){
  454.                 break;
  455.             }else if (code == MENU_ADD){
  456.                 HOST *hst = newhost("");
  457.                 if (hst != NULL){
  458.                     if (hst->edit(helpfile)==0){
  459.                         add(hst);
  460.                         write ();
  461.                     }else{
  462.                         delete hst;
  463.                     }
  464.                 }
  465.             }else if(nb>0){
  466.                 // Edit one hosts
  467.                 HOST *hst = tbsort[choice];
  468.                 int ok = hst->edit(helpfile);
  469.                 if (ok != -1){
  470.                     if (ok == 1) remove_del (hst);
  471.                     write();
  472.                 }
  473.             }
  474.             for (i=0; i<nb; i++) free ((char*)(menuopt[i*2+1]));
  475.             delete [] menuopt;
  476.         }
  477.     }
  478.     return  ret;
  479. }
  480. /*
  481.     Edit the file /etc/hosts
  482. */
  483. void netconf_edithosts()
  484. {
  485.     HOSTS hosts;
  486.     if (hosts.read () != -1){
  487.         hosts.edit(ETC_HOSTS,help_hosts);
  488.     }
  489. }
  490. /*
  491.     Edit the file /etc/networks
  492. */
  493. void netconf_editnet()
  494. {
  495.     NETWORKS nets;
  496.     if (nets.read () != -1){
  497.         nets.edit(ETC_NETWORKS,help_networks);
  498.     }
  499. }
  500.  
  501. #ifdef TEST
  502.  
  503. int main (int , char *[])
  504. {
  505.     HOSTS hosts;
  506.     hosts.read ();
  507.     hosts.write ();
  508.     return 0;
  509. }
  510. #endif
  511.  
  512.